package sk.fritz.megafonsms.formparser;

import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Vector;

import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;

import org.kxml2.io.KXmlParser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import sk.fritz.megafonsms.formmodel.Option;

public class FormParser implements Runnable {

	private Vector listeners;
	private Vector errorListeners;

	private InputStream input;
	
	private KXmlParser p;
	
	private String encoding;
	
	private HttpConnection connection;
	
	public FormParser(String url) throws IOException {
		this();

		this.connection = (HttpConnection) Connector.open(url);
		this.input = connection.openInputStream();
		this.encoding = connection.getEncoding();
		
		int response = connection.getResponseCode();
		if (response != HttpConnection.HTTP_OK) {
			throw new IOException("Server returned: "
					+ connection.getResponseMessage());
		}
	}

	public FormParser(InputStream input) {
		this();
		this.input = input;	
		this.encoding = null;
	}
	
	private FormParser() {
		this.listeners = new Vector();
		this.errorListeners = new Vector();
		p = new KXmlParser();
		try {
			p.setFeature("http://xmlpull.org/v1/doc/features.html#relaxed",
					true);
		} catch (XmlPullParserException igored) {
		}
	}

	public void run() {

		try {
			p.setInput(input, encoding);

			int eventType = p.getEventType();
			do {
				if (eventType == XmlPullParser.START_DOCUMENT) {
					System.out.println("Start document");
				} else if (eventType == XmlPullParser.END_DOCUMENT) {
					System.out.println("End document");
				} else if (eventType == XmlPullParser.START_TAG) {
					if (p.getName().equals("form")) {
						processForm();
					}
				} else if (eventType == XmlPullParser.END_TAG) {
					// nothing
				} else if (eventType == XmlPullParser.TEXT) {
					// nothing
				}
				eventType = p.next();
			} while (eventType != XmlPullParser.END_DOCUMENT);

		} catch (XmlPullParserException ex) {
			Enumeration enum = this.errorListeners.elements();
			while (enum.hasMoreElements()) {
				FormErrorListener l = (FormErrorListener) enum.nextElement();
				l.error(ex);
			}

		} catch (IOException ioEx) {
			Enumeration enum = this.errorListeners.elements();
			while (enum.hasMoreElements()) {
				FormErrorListener l = (FormErrorListener) enum.nextElement();
				l.error(ioEx);
			}
		} finally {
			if (input != null)
				try {
					input.close();
				} catch (IOException e) {}
			if (connection != null)
				try {
					connection.close();
				} catch (IOException e) {}
		}

	}

	private void processForm() throws XmlPullParserException,
			IOException {
		Enumeration enum;
		p.require(XmlPullParser.START_TAG, null, "form");

		// inform listeners that we have FORM!
		enum = this.listeners.elements();
		while (enum.hasMoreElements()) {
			FormListener l = (FormListener) enum.nextElement();
			l.form(p.getAttributeValue(null, "id"), p.getAttributeValue(null,
					"action"), p.getAttributeValue(null, "method"), p.getAttributeValue(null, "enctype"));
		}

		int eventType = p.getEventType();
		do {
			if (eventType == XmlPullParser.START_TAG) {
				if (p.getName().equals("input")) {
					// process input element
					enum = this.listeners.elements();
					while (enum.hasMoreElements()) {
						FormListener l = (FormListener) enum.nextElement();
						String s = p.getAttributeValue(null, "maxlength");
						Integer i = null;
						if (s != null)
							i = Integer.valueOf(s);
						l.input(p.getAttributeValue(null, "type"),
								p.getAttributeValue(null, "name"),
								p.getAttributeValue(null, "value"),
								i);
					}
				} else if (p.getName().equals("select")) {
					processSelect();
				} else if (p.getName().equals("textarea")) {
					enum = this.listeners.elements();
					while (enum.hasMoreElements()) {
						FormListener l = (FormListener) enum.nextElement();
						l.input("textarea", p.getAttributeValue(null, "name"),
								null /* should be replaced by tag text */, null);
					}
				}
			}
			eventType = p.next();
		} while (eventType != XmlPullParser.END_TAG || !p.getName().equals("form"));

	}

	private void processSelect() throws XmlPullParserException, IOException {
		p.require(XmlPullParser.START_TAG, null, "select");

		String selectName = p.getAttributeValue(null, "name");
		Vector options = new Vector();

		int eventType = p.getEventType();
		Option o = null;
		Option selected = null;
		do {
			if (eventType == XmlPullParser.START_TAG && p.getName().equals("option")) {
				o = new Option(p.getAttributeValue(null, "value"), null);
				if (p.getAttributeValue(null, "selected") != null) 
					selected = o;
				options.addElement(o);
			} else if (eventType == XmlPullParser.TEXT && o != null) {
				o.setText(p.getText().trim());
			} else if (eventType == XmlPullParser.END_TAG && p.getName().equals("option")) {
				o = null;
			}

			eventType = p.next();
		} while (eventType != XmlPullParser.END_TAG || !p.getName().equals("select"));
		
		Enumeration enum = this.listeners.elements();
		Option[] opts = new Option[options.size()];
		options.copyInto(opts);
		int selIndex = selected == null ? 0 : options.indexOf(selected);
		while (enum.hasMoreElements()) {
			FormListener l = (FormListener) enum.nextElement();
			l.select(selectName, opts, selIndex);
		}
	}

	public void addListener(FormListener listener) {
		this.listeners.addElement(listener);
	}

	public void removeListener(FormListener listener) {
		this.listeners.removeElement(listener);
	}
	
	public void addErrorListener(FormErrorListener l) {
		this.errorListeners.addElement(l);
	}
	
	public void removeListener(FormErrorListener l) {
		this.listeners.removeElement(l);
	}

}